﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mimoza.AgentLayer.Communication;
using Mimoza.Transport;

namespace Mimoza.ServiceLayer
{
    public class ServicePolicySynchronizer : BaseObject
    {
        public ServicePolicySynchronizer(Configuration config)
            : base(config)
        {
            RequestPolicySync.RegisterHandler(
                new RequestPolicySync.Handler(ProcessRequestPolicySync));
            ReplyPolicySync.RegisterInTransport();

            RequestPolicies.RegisterHandler(
                new RequestPolicies.Handler(ProcessRequestPolicy));
                ReplyPolicies.RegisterInTransport();
        }

        ReplyPolicySync ProcessRequestPolicySync(RequestPolicySync request)
        {
            ObjectLayer.Host host = GetHost(request.HostId);
            ObjectLayer.Container hostContainer = host.Parent;

            ReplyPolicySync reply = new ReplyPolicySync();
            
            reply.ServerSyncId = hostContainer.EffectivePolicyID;
            reply.HostModifiedId = host.ModificationID;
            if (reply.ServerSyncId != request.LastSyncId || reply.HostModifiedId != request.HostModifiedId)
            {
                reply.IsSyncRequeried = true;
            }
            
            Common.Logger.Log.Info("ServicePolicySynchronizer.ProcessRequestPolicySync hostId - '"
                + request.HostId.ToString() + "' hostEffectiveId - '" + request.LastSyncId.ToString() +
                "' serverEffectiveId - '" + reply.ServerSyncId);

            if (reply.ServerSyncId != request.LastSyncId)
            {
                Common.Logger.Log.Info("ServicePolicySynchronizer.ProcessRequestPolicySync hostId - '"
                    + request.HostId.ToString() + "'. Need to sync policy.");
            }
            if (reply.HostModifiedId != request.HostModifiedId)
            {
                Common.Logger.Log.Info("ServicePolicySynchronizer.ProcessRequestPolicySync hostId - '"
                    + request.HostId.ToString() + "'. Need to sync host settings.");
            }

            SaveHostConnectionTime(host);

            return reply;
        }

        ReplyPolicies ProcessRequestPolicy(RequestPolicies request)
        {
            ObjectLayer.Host host = GetHost(request.HostId);
            ObjectLayer.Container hostContainer = host.Parent;

            ReplyPolicies reply = new ReplyPolicies();

            reply.EffectivePolicyId = hostContainer.EffectivePolicyID;
            reply.PoliciesRecords = null;

            bool bNeedSync = false;
            if (hostContainer.EffectivePolicyID != request.LastSyncId ||
                host.ModificationID != request.HostModifiedId) bNeedSync = true;

            Common.Logger.Log.Info("ServicePolicySynchronizer.ProcessRequestPolicy hostId - '"
                + request.HostId.ToString() + "' serverEffectiveId - '" + reply.EffectivePolicyId.ToString() +
                "' NeedSync - '" + bNeedSync.ToString() + "'.");

            if (bNeedSync)
            {
                IEnumerable<ObjectLayer.Policy> hostPolicies = hostContainer.GetEffectivePolicy();
                if (hostPolicies != null)
                {
                    reply.PoliciesRecords = new Mimoza.Common.PolicyRecord[hostPolicies.Count()];
                    int c = 0;
                    foreach (ObjectLayer.Policy policy in hostPolicies)
                    {
                        reply.PoliciesRecords[c++] = policy.Record;
                        Common.Logger.Log.Info("ServicePolicySynchronizer.ProcessRequestPolicy policy - " + c.ToString() +
                            ":'" + policy.ID.ToString() + "'.");
                    }
                }
                else
                {
                    reply.PoliciesRecords = new Mimoza.Common.PolicyRecord[0];
                }   
            }

            if (bNeedSync)
            {
                reply.ServerHostRecord = host.Record;
            }

            return reply;
        }

        void SaveHostConnectionTime(ObjectLayer.Host host)
        {
            using (new NotificationAutoSet("LastConnectionDate"))
            {
                host.LastConnectionDate = DateTime.Now;
                ObjectLayer.HostRepository.Update(host);
            }
        }

        ObjectLayer.Host GetHost(Guid hostId)
        {
            ObjectLayer.Host host = ObjectLayer.HostRepository.GetHostByID(hostId);
            if (host == null)
            {
                Common.Logger.Log.Error("ServicePolicySynchronizer.GetHostContainer ERROR hostId - '"
                    + hostId.ToString() + "' not found in database.");
                throw new Mimoza.ServiceLayer.AgentDontRegistered();
            }
            if (host.Parent == null)
            {
                Common.Logger.Log.Error("ServicePolicySynchronizer.GetHostContainer ERROR hostId - '"
                    + hostId.ToString() + "' doesn't have container. Parent is null.");
                throw new Mimoza.ServiceLayer.AgentDontHaveConatiner();
            }

            return host;
        }

    }
}